<template>
	<view class="vi_calendar">
		<view class="vi_calendar_head vi_fCenter">
			<!-- 其他按钮，非单选且带时间 -->
			<view class="vi_calendar_addonL" v-if="pickTime&&(isCheckbox||isRange)">
				<!-- 添加 -->
				<vi-style-controller v-if="isCheckbox" @click="itemAdd('item')"
					:type="setting.type"
					:color="color"
					:textColor="textColor"
					radius="0.25em"
					:borderWidth="0"
					:plain="plain"
					:disabled="disabled||!tempDate"
					:readOnly="readOnly"
					active>
					<text class="vi_calendar_button iconfont" :class="iconSetting.add"></text>
				</vi-style-controller>
				<view v-else-if="isRange">
					<vi-style-controller v-if="!selectList.length||selectList.length>=2" @click="itemAdd('start')"
						:type="setting.type"
						:color="color"
						:textColor="textColor"
						radius="0.25em"
						:borderWidth="0"
						:plain="plain"
						:disabled="disabled||!tempDate"
						:readOnly="readOnly"
						active>
						<text class="vi_calendar_button">{{textSetting.start}}</text>
					</vi-style-controller>
					<vi-style-controller v-else @click="itemAdd('end')"
						:type="setting.type"
						:color="color"
						:textColor="textColor"
						radius="0.25em"
						:borderWidth="0"
						:plain="plain"
						:disabled="disabled||!tempDate"
						:readOnly="readOnly"
						active>
						<text class="vi_calendar_button">{{textSetting.end}}</text>
					</vi-style-controller>
				</view>
			</view>
			<!-- 上一月按钮 -->
			<view class="vi_calendar_preMonth" @click="changeMonth(-1)">
				<text class="iconfont" :class="iconSetting.prevMonth"></text>
			</view>
			<!-- 年月时间显示 -->
			<view class="vi_calendar_currShow vi_fCenter">
				<view class="vi_calendar_curr" @click="openPicker('Y')">{{showYear}}</view>
				<view class="vi_calendar_curr" @click="openPicker('M')">{{showMonth}}</view>
				<view class="vi_calendar_curr" @click="openPicker('T')" v-if="pickTime">
					<vi-style-controller
						control="text"
						:type="setting.type"
						:color="color"
						:textColor="textColor"
						active>
						{{showTime}}
					</vi-style-controller>
				</view>
			</view>
			<!-- 下一月按钮 -->
			<view class="vi_calendar_nextMonth" @click="changeMonth(1)">
				<text class="iconfont" :class="iconSetting.nextMonth"></text>
			</view>
			<!-- 右按钮 -->
			<view class="vi_calendar_addonR" @click="toToday">
				<vi-style-controller
					:type="setting.type"
					:color="color"
					:textColor="textColor"
					radius="0.25em"
					:borderWidth="0"
					:plain="!(isRadio&&today==selectList[0])"
					active>
					<text class="vi_calendar_button">{{textSetting.todayShot}}</text>
				</vi-style-controller>
			</view>
		</view>
		<view class="vi_calendar_body">
			<!-- 拾取器 年 -->
			<vi-drawer ref="pickerY" point="top" position="absolute" bgColor="transparent" :maskBgColor="setting.pickerMaskBgColor" width="75%">
				<view class="vi_calendar_picker">
					<view class="vi_calendar_pickerHead" :style="weekStyle">
						<view class="iconfont" :class="iconSetting.prevYear" @click="pickerTurnPage(-1)"></view>
						<view>
							<text>{{pickerListYear[0]}}</text>
							<text class="vi_mx">-</text>
							<text>{{pickerListYear[pickerListYear.length-1]}}</text>
						</view>
						<view class="iconfont" :class="iconSetting.nextYear" @click="pickerTurnPage(1)"></view>
					</view>
					<view class="vi_calendar_pickerList">
						<view class="vi_calendar_pickerItem" :style="{'width':'33.3%'}" v-for="(item, index) in pickerListYear" :key="index">
							<vi-style-controller @click="pickerClickYear(item)"
								compName="calendarDate"
								:type="setting.type"
								:color="color"
								:textColor="textColor"
								:size="setting.size"
								width="100%"
								:height="setting.rowHeight"
								:borderWidth="plain?1:0"
								:radius="pickerRadius"
								:plain="plain"
								:active="currYear==item">
								<text>{{item}}</text>
							</vi-style-controller>
						</view>
					</view>
				</view>
			</vi-drawer>
			<!-- 拾取器 月 -->
			<vi-drawer ref="pickerM" point="top" position="absolute" bgColor="transparent" :maskBgColor="setting.pickerMaskBgColor" width="75%">
				<view class="vi_calendar_picker vi_calendar_pt">
					<view class="vi_calendar_pickerList">
						<view class="vi_calendar_pickerItem" :style="{'width':'33.3%'}" v-for="index of dicMonth" :key="index">
							<vi-style-controller @click="pickerClickMonth(index)"
								compName="calendarDate"
								:type="setting.type"
								:color="color"
								:textColor="textColor"
								:size="setting.size"
								width="100%"
								:height="setting.rowHeight"
								:borderWidth="plain?1:0"
								:radius="pickerRadius"
								:plain="plain"
								:active="currMonth==index">
								<text>{{index}}月</text>
							</vi-style-controller>
						</view>
					</view>
				</view>
			</vi-drawer>
			<!-- 选择列表 -->
			<vi-drawer ref="selectList" position="absolute" :width="pickTime?'75%':'60%'" v-if="isCheckbox">
				<scroll-view scroll-y class="vi_calendar_selectList" @touchmove.stop>
					<view class="vi_calendar_selectItem" v-for="(item, index) in selectListSort" :key="index">
						<!-- 标题 -->
						<view class="">
							{{dateFormat(item, {format:setting.tipsFormat})}}
						</view>
						<!-- 删除按钮 -->
						<view class="vi_delete" @click="delItem(item)">
							<vi-style-controller
								type="bgError"
								radius="circle"
								width="1.2em"
								height="1.2em"
								:disabled="disabled"
								:readOnly="readOnly"
								borderBox
								active>
								<text class="iconfont" :class="iconSetting.delete"></text>
							</vi-style-controller>
						</view>
					</view>
				</scroll-view>
			</vi-drawer>
			<!-- 背景 -->
			<view class="vi_calendar_bgMonth vi_fCenter">
				<text :style="bgMonthStyle">{{thisMonth}}</text>
			</view>
			<!-- 星期 -->
			<view class="vi_calendar_rowWeek" :style="weekStyle">
				<view class="vi_fCenter vi_calendar_item" v-for="(item, index) in weekSetting" :key="index">{{item}}</view>
			</view>
			<!-- 日期 -->
			<view class="vi_calendar_rowDate" v-for="(row, index) in showList" :key="index">
				<view class="vi_calendar_item" :style="{'margin':`${setting.rowSpace}em 0`}" v-for="(item, idx) in row" :key="idx" @click="itemClick(item)">
					<!-- 背景 -->
					<view class="vi_calendar_actBg" :style="{'opacity':setting.rangeBgOpacity}" v-if="item.bgActive">
						<vi-style-controller
							:compName="useTag?'calendarDateTag':'calendarDate'"
							:type="item.type=='weekend'&&customWeekend&&!item.active?weekendType:setting.type"
							:color="item.type=='weekend'&&customWeekend&&!item.active?weekendColor:color"
							:radius="item.bgRadius"
							:size="setting.size"
							width="100%"
							:height="rowHeightCurr"
							:disabled="item.disabled||disabled"
							:readOnly="item.readOnly||readOnly"
							active>
						</vi-style-controller>
					</view>
					<view class="vi_calendar_itemBox">
						<vi-style-controller
							:compName="useTag?'calendarDateTag':'calendarDate'"
							:type="item.active||item.disabled||disabled? setting.type :(item.subActive? setting.subType :(item.type=='weekend'&&customWeekend? weekendType :''))"
							:color="item.active||item.disabled||disabled? color :(item.subActive? subColor :(item.type=='weekend'&&customWeekend? weekendColor :''))"
							:textColor="item.active||item.disabled||disabled? textColor :(item.subActive? subTextColor :(item.type=='weekend'&&customWeekend? weekendTextColor :''))"
							:radius="item.radius||radius"
							:size="setting.size"
							width="100%"
							:height="rowHeightCurr"
							:borderWidth="plain||item.subActive?1:0"
							:borderColor="item.borderColor"
							:disabled="item.disabled||disabled"
							:readOnly="item.readOnly||readOnly"
							:plain="item.subActive?subPlain:(plain||(!item.active&&item.type=='weekend'&&customWeekend))"
							borderBox
							:active="item.active||item.subActive||(item.type=='weekend'&&customWeekend)">
							<view class="vi_calendar_itemInbox">
								<view class="vi_fs12">{{item.name}}</view>
								<view v-if="useTag">
									<text v-if="!item.tagActive||item.disabled||disabled">{{item.tag ||""}}</text>
									<vi-style-controller v-else
										control="text"
										:type="!item.active? setting.type :''"
										:color="!item.active? color :''"
										:textColor="!item.active? textColor :''"
										:active="!item.active? true:false">
										<text>{{item.tag ||""}}</text>
									</vi-style-controller>
								</view>
							</view>
						</vi-style-controller>
					</view>
				</view>
			</view>
		</view>
		<view class="vi_calendar_tips" v-if="setting.useToolbar">
			<view class="vi_calendar_text">
				<view class="vi_calendar_tipbox" v-if="!isCheckbox">
					<text>{{textSetting.dateSelected}}：</text>
					<text class="vi_mr vi_fs12 iconfont" :class="[iconSetting.calendar, {'color-tips':!selectList.length}]"></text>
				</view>
				<vi-style-controller v-else @click="showSelectList"
					control="text"
					:type="setting.type"
					:color="color"
					:textColor="textColor"
					:disabled="!selectList.length"
					active>
					<text>{{textSetting.dateSelected}}({{selectList.length}})：</text>
				</vi-style-controller>
			</view>
			<view class="vi_calendar_tipbox" v-if="isRadio">
				<text class="vi_mr2">{{dateFormat(selectList[0],{format:setting.tipsFormat})||""}}</text>
				<text class="vi_mr vi_fs12 iconfont" :class="iconSetting.time" v-if="pickTime"></text>
				<text v-if="pickTime">{{showTime}}</text>
			</view>
			<view class="vi_calendar_textcut" v-if="isCheckbox">
				<text class="vi_inlineBlock" v-for="(val, index) in selectListSort" :key="index">{{(index>0?"、":"")+dateFormat(val,{format:setting.tipsFormat})}}</text>
			</view>
			<view class="vi_calendar_scroll" :style="{'width':'calc(100% - '+textSetting.dateSelected.length+'em - 3.3em)'}" v-if="isRange">
				<scroll-view scroll-x>
					{{selectList[0]? dateFormat(selectList[0],{format:setting.tipsFormat}) :""}}
					<text class="vi_mx vi_fs12 iconfont" :class="iconSetting.to" style="display: inline;" v-if="selectList[1]"></text>
					{{selectList[1]? dateFormat(selectList[1],{format:setting.tipsFormat}) :""}}
				</scroll-view>
			</view>
		</view>
		<view class="vi_calendar_submitBtn" v-if="setting.useSubmitButton">
			<vi-button @click="submit"
				:type="setting.type"
				:color="color"
				:textColor="textColor"
				:radius="setting.submitRadius"
				:size="submitSize"
				:plain="submitPlain"
				:width="submitWidth||'100%'"
				:height="submitHeight"
				:disabled="disabled||disabledSubmit"
				:readOnly="readOnly">{{textSetting.confirm}}</vi-button>
		</view>
		
		<!-- 拾取器 时间 -->
		<!-- 兼容问题：如果开启滚动工具条，popup的scale样式会影响工具条滚动位置计算，导致工具条的实际时间值错误(每次打开值递增)。
			解决方案：
			1、popup弹出位置使用fade，禁用scale样式。
			2、clock关闭滚动工具，useScrollBox=false。
			3、在popup动画完成后手动执行滚动位置初始化，useScrollBox=true，selfInitScrollBox=true，方法initScroll -->
		<vi-popup ref="pickerT" point="center" width="22em" radius="0.5em" v-if="pickTime" @opened="pickerTOpened">
			<view class="vi_calendar_timePicker">
				<vi-clock ref="clock"
					radius="8em"
					tabbarWidth="100%"
					toolWidth="33%"
					:tabRadius="pickerRadius"
					:plain="plain"
					:value="timeValue"
					:useSecond="useSecond"
					:useSubmit="false"
					useScrollBox
					selfInitScrollBox
					:text="textSetting"
					@change="pickerTimeChange"></vi-clock>
			</view>
		</vi-popup>
	</view>
</template>

<script>
	import lunarCalendar from "./calendar.js"
	export default {
		name:"viCalendar",
		props: {
			type:{
				type:[String,null],
				default:null
			},
			color:{
				type:[String,null],
				default:""
			},
			textColor:{
				type:[String,null],
				default:""
			},
			radius:{
				type:[Number,String,null],
				default:""
			},
			size:{
				type:[String,null],
				default:null
			},
			plain:{
				type:[Boolean,null],
				default:false
			},
			//用于多选模式且开启时间选择的次级主题，显示临时选中的日期
			subType:{
				type:[String,null],
				default:null
			},
			//用于多选模式且开启时间选择的次级自定义主题，显示临时选中的日期
			subColor:{
				type:[String,null],
				default:""
			},
			//用于多选模式且开启时间选择的次级固定文字色，显示临时选中的日期
			subTextColor:{
				type:[String,null],
				default:""
			},
			subPlain:{
				type:[Boolean,null],
				default:false
			},
			value:{
				type:[String,Number,Date,Array,null],
				default:""
			},
			formatSet:{
				type:[Object,null],
				default:()=>({})
			},
			weekSet:{
				type:[Object,null],
				default:()=>({})
			},
			//星期条高度，单位em
			weekHeight:{
				type:[Number,null],
				default:0
			},
			//日期单元格高
			rowHeight:{
				type:[Number,null],
				default:0
			},
			//日期行间距
			rowSpace:{
				type:[Number,null],
				default:null
			},
			//周末主题色
			weekendType:{
				type:[String,null],
				default:""
			},
			//周末自定义色
			weekendColor:{
				type:[String,null],
				default:""
			},
			weekendTextColor:{
				type:[String,null],
				default:""
			},
			//radio单选、checkbox多选、range选区
			mode:{
				type:[String,null],
				default:""
			},
			//选择时间，开启后时间值并入日期值
			pickTime:{
				type:[Boolean,null],
				default:false
			},
			useSecond:{
				type:[Boolean,null],
				default:false
			},
			//选区背景透明度
			rangeBgOpacity:{
				type:[Number,null],
				default:null
			},
			//拾取器按钮圆角
			pickerRadius:{
				type:[String,Number,null],
				default:""
			},
			pickerMaskBgColor:{
				type:[String,null],
				default:""
			},
			start:{
				type:[Number,String,Date,null],
				default:""
			},
			end:{
				type:[Number,String,Date,null],
				default:""
			},
			//最少选择，多选用
			min:{
				type:[Number,null],
				default:0
			},
			//最多选择，多选用
			max:{
				type:[Number,null],
				default:0
			},
			//使用农历标签
			useLunar:{
				type:[Boolean,null],
				default:false
			},
			//自定义标签
			tagList:{
				type:[Array,null],
				default:()=>[
					// {
					// 	name:"",	//标题
					// 	value:"",	//时间，天
					//	event:"",	//事件名
					// }
				]
			},
			//工具栏，显示已选
			useToolbar:{
				type:[Boolean,null],
				default:null
			},
			//状态提示，日期格式
			tipsFormat:{
				type:[String,null],
				default:""
			},
			//提交按钮
			useSubmitButton:{
				type:[Boolean,null],
				default:null
			},
			submitWidth:{
				type:[String,Number,null],
				default:0
			},
			submitRadius:{
				type:[String,Number,null],
				default:null
			},
			submitSize:{
				type:[String,null],
				default:null
			},
			submitPlain:{
				type:[Boolean,null],
				default:false
			},
			submitHeight:{
				type:[Number,String,null],
				default:""
			},
			//返回结果格式
			resFormat:{
				type:[String,null],
				default:""
			},
			disabled:{
				type:[Boolean,null],
				default:false
			},
			readOnly:{
				type:[Boolean,null],
				default:false
			},
			icon:{
				type:[Object,null],
				default:()=>({})
			},
			text:{
				type:[Object,null],
				default:()=>({})
			},
		},
		data() {
			return {
				dicFormat:{
					year: "YYYY年",
					month: "MM月",
					time: "hh:mm:ss",
					timeM: "hh:mm",
				},
				dicWeek:{
					0: "日",
					1: "一",
					2: "二",
					3: "三",
					4: "四",
					5: "五",
					6: "六"
				},
				selectList:[],	//选中值
				tempDate:null,	//临时选择日期，非单选且选择时间时用
				baseTime:null,	//基准时间，指示当月
				dateList:[],
				inStart:null,	//开始范围
				inEnd:null,		//结束范围
				timeValue:{},	//时间值，{hour:0,minute:0,second:0}
				dicIcon:{
					calendar: "icon-calendar",
					time: "icon-clock",
					to: "icon-to",
					prevMonth: "icon-arr-left",
					nextMonth: "icon-arr-right",
					prevYear: "icon-arr-double-left",
					nextYear: "icon-arr-double-right",
					delete: "icon-delete-small",
					add: "icon-add",
				},
				dicText:{
					confirm: "确定",
					todayShot: "今",
					today: "今日",
					start: "开始",
					end: "结束",
					dateSelected: "已选",
					tipDateEmptyError: "请选择一个日期",
					tipDateMinError: "请至少选择${min}个日期",
					tipDateMaxError: "请选择${min}至${max}个日期",
					tipDateRangeError: "请选择日期范围",
				},
				pickerPage:0,			//拾取器翻页，用于生成列表
				pickerListYear:[],	//年拾取器数据列表
			}
		},
		computed: {
			//将默认值内含到css、计算属性等地方，只内含真值
			//规避特殊使用的情况下，由prop传入undefined、null等无效数据导致的，默认值失效问题。例如组件嵌套且需要组件间参数传递
			//HBuilder X3.3.13; 微信开发者工具stable 1.05.2111300
			//微信小程序会对传入的undefined、null值根据参数类型输出不同空值(false、""、null、0)，参数类型为null或未指定参数类型则输出null
			//H5会对传入的undefined取默认值，未设默认值则输出undefined。对传入的null值固定输出null
			//做参数传递时需警惕两者行为不同而造成的陷阱，主要问题出现在微信小程序的空值转化，输出非用户传入的空值、假值，使默认真值丢失
			//兼容空值取默认值的可行方案目前为，参数类型加入null如[Boolean,null]，判断传入参数是否为定义的类型，是则使用，否则赋予默认值
			setting(){
				let tipsFormat = "YYYY-MM-DD";
				if(this.pickTime){
					tipsFormat += " hh:mm";
					if(this.useSecond){
						tipsFormat += ":ss"
					}
				}
				return {
					type: this.$api.isDefined(this.type)? this.type :"primary",
					subType: this.$api.isDefined(this.subType)? this.subType :"grey",
					size: this.$api.isDefined(this.size)? this.size :"md",
					rowHeight: this.rowHeight? this.rowHeight +"em" :"",
					rowSpace: this.$api.isValue(this.rowSpace)? this.rowSpace/2 :0.1,//除2用于css
					rangeBgOpacity: this.$api.isValue(this.rangeBgOpacity)? this.rangeBgOpacity :0.1,
					pickerMaskBgColor: this.pickerMaskBgColor ||"rgba(0,0,0,0.2)",
					useToolbar: this.$api.isBoolean(this.useToolbar)? this.useToolbar :true,
					tipsFormat: this.tipsFormat ||tipsFormat,
					useSubmitButton: this.$api.isBoolean(this.useSubmitButton)? this.useSubmitButton :true,
					submitRadius: this.$api.isDefined(this.submitRadius)? this.submitRadius :"circle",
					min: this.min ||1,
				}
			},
			formatSetting(){
				if(this.$api.isObject(this.formatSet)){
					return Object.assign({}, this.dicFormat, this.formatSet)
				}
				return this.dicFormat
			},
			//当月，数字
			thisMonth(){
				return this.baseTime? new Date(this.baseTime).getMonth()+1 :0
			},
			dicMonth(){
				let res =[];
				for(let i=1; i<=12; i++){
					res.push(i)
				}
				return res
			},
			//今天，数字
			today(){
				return this.clearTime(Date.now())
			},
			//选中年，数字
			currYear(){
				return new Date(this.baseTime).getFullYear();
			},
			//选中月，数字
			currMonth(){
				return new Date(this.baseTime).getMonth() +1;
			},
			//当年显示字符串
			showYear(){
				return this.baseTime? this.dateFormat(this.baseTime, {format:this.formatSetting.year}) :""
			},
			//当月显示字符串
			showMonth(){
				return this.baseTime? this.dateFormat(this.baseTime, {format:this.formatSetting.month}) :""
			},
			//当前时间显示字符串
			showTime(){
				let str = this.useSecond? this.formatSetting.time :this.formatSetting.timeM,
					timeValue = this.timeValue,
					h = timeValue.hour,
					hh = h<10? "0"+h :h,
					m = timeValue.minute,
					mm = m<10? "0"+m :m,
					s = timeValue.second,
					ss = s<10? "0"+s :s;
				str = str.replace("hh", hh);
				str = str.replace("h", h);
				str = str.replace("mm", mm);
				str = str.replace("m", m);
				str = str.replace("ss", ss);
				str = str.replace("s", s);
				return str
			},
			//重构日历数据，加入行结构
			showList(){
				let arr = [];
				if(this.dateList.length ==42){
					for(let i=0; i<6; i++){
						let subArr = [];
						for(let j=0; j<7; j++){
							subArr.push(this.dateList[i*7+j])
						}
						arr.push(subArr);
					}
					return arr
				}
				return []
			},
			//重构选择数据，重排序
			selectListSort(){
				if(this.isCheckbox){
					return this.selectList.sort(function(a,b){
						return a-b
					})
				}
				return []
			},
			//重构标签列表，清理日期中的时间值
			inTagList(){
				let res =[],
					list = this.tagList||[];
				for(let i=0,len=list.length; i<len; i++){
					let item = list[i];
					item["value"] = this.clearTime(item.value);
					res.push(item);
				}
				return res
			},
			isRadio(){
				return !this.mode||this.mode=="radio"
			},
			isCheckbox(){
				return this.mode=="checkbox"
			},
			isRange(){
				return this.mode=="range"
			},
			isVirtual(){
				return this.pickTime&&(this.isCheckbox||this.isRange)
			},
			//是否开启标签（农历或自定义）
			useTag(){
				return this.useLunar || (this.tagList&&this.tagList.length>0)
			},
			//当前行高，带标签（开启标签加1.5em）
			rowHeightCurr(){
				return this.rowHeight? this.rowHeight +(this.useTag? 1.5:0) +"em" :""
			},
			//星期栏，设置高
			weekStyle(){
				return `height:${this.weekHeight||2.5}em;`
			},
			//背景月尺寸
			bgMonthStyle(){
				let h = this.rowSpace ||0;
				if(this.rowHeight){
					h += this.rowHeight +(this.useTag? 1.5:0);
				}else{
					//增加星期栏高，默认使用最小高度2em
					h += this.useTag? 3.5:2;
				}
				let H = h *550 +(this.weekHeight? this.weekHeight :2);
				return `font-size:${parseInt(H)}%;`
			},
			customWeekend(){
				return !!this.weekendType||this.$api.isColor(this.weekendColor)
			},
			//提交按钮禁用状态
			disabledSubmit(){
				if(this.isRadio){
					return this.selectList.length <1
				}else if(this.isCheckbox){
					let num = this.selectList.length;
					return (this.setting.min>num)||(this.max&&this.max<=num)||false
				}
				return this.selectList.length !=2
			},
			weekSetting(){
				if(this.$api.isObject(this.weekSet)){
					return Object.assign({}, this.dicWeek, this.weekSet)
				}
				return this.dicWeek
			},
			iconSetting(){
				if(this.$api.isObject(this.icon)){
					return Object.assign({},this.dicIcon,this.icon)
				}
				return this.dicIcon
			},
			textSetting(){
				if(this.$api.isObject(this.text)){
					return Object.assign({},this.dicText,this.text)
				}
				return this.dicText
			}
		},
		methods: {
			//基础
			dateFormat(date, options){
				return this.$api.dateFormat(date, options);
			},
			//清除时间，基础单位保留日
			clearTime(value){
				let temp = new Date(value);
				temp.setHours(0);
				temp.setMinutes(0);
				temp.setSeconds(0);
				temp.setMilliseconds(0);
				return temp.getTime()
			},
			//根据时间戳取得基础时间
			getBase(value){
				let temp = new Date(value);
				temp.setDate(1);
				return this.clearTime(temp);
			},
			//清除键
			clearKey(key){
				if(key){
					for(let item of this.dateList){
						delete item[key]
					}
				}
			},
			//转到今日
			toToday(){
				if(this.isRadio){
					this.selectList = [this.today];
					this.$emit("change", this.getData());
				}
				this.baseTime = this.getBase(this.today)
				this.refresh();
			},
			//变更月，数值增减
			changeMonth(num){
				this.baseTime = this.$api.datePoint(this.baseTime, {month:num});
				this.refresh()
			},
			//日期点击事件，非special模式均立即触发事件
			itemClick(item){
				if(item.event){
					this.$emit("event", {
						event: item.event,
						item
					})
				}
				if(item.disabled||item.readOnly||this.disabled||this.readOnly){
					return
				}
				if(this.isRadio){
					//单选
					this.clearKey("active");
					item["active"] = true;
					this.selectList = [item.value];
					//刷新圆角
					this.computeBorder();
					this.$emit("change", this.getData());
				}else if(this.isVirtual){
					//特殊选择，激活临时日期
					this.clearKey("active");
					item["active"] = true;
					this.tempDate = item.value;
					//刷新圆角
					this.computeBorder();
				}else if(this.isCheckbox){
					//多选
					//清除
					if(item.active){
						this.deleteItem(item)
					}else{//选中
						this.selectItem(item)
					}
					//刷新圆角，如果有最大选择数量限制，刷新列表
					if(this.max){
						this.refresh()
					}else{
						this.computeBorder()
					}
					this.$emit("change", this.getData());
				}else if(this.isRange){
					//选区，数组只能存在两个值
					let len = this.selectList.length;
					if(len>=2 || len==0){
						this.selectList=[item.value]
					}else if(item.value>this.selectList[0]){
						this.selectList.push(item.value)
					}else{
						this.selectList.unshift(item.value)
					}
					//刷新数据
					this.refresh();
					if(this.selectList.length==2){
						this.$emit("change", this.getData());
					}
				}
				this.$forceUpdate();
			},
			//添加日期时间
			itemAdd(type){
				let date = new Date(this.tempDate),
					timeObj = this.timeValue,
					res;
				date.setHours(timeObj.hour, timeObj.minute, timeObj.second);
				res = date.getTime();
				switch(type){
					case "item"://多选
						//检测选择列表是否存在
						if(!this.selectList.includes(res)){
							this.selectList.push(res)
						}
						break;
					case "start"://起始
						this.selectList=[res];
						break;
					case "end"://结束
						if(res>this.selectList[0]){
							this.selectList.push(res)
						}else{
							this.selectList.unshift(res)
						}
						break;
				}
				//刷新数据
				this.refresh();
				if(["item","end"].includes(type)){
					this.$emit("change", this.getData());
				}
			},
			//显示选择列表
			showSelectList(){
				this.$refs.selectList.open()
			},
			//在选择列表删除选中
			delItem(item){
				let idx = this.selectList.indexOf(item);
				if(idx != -1){
					this.selectList.splice(idx, 1)
				}
				//刷新显示
				this.refresh();
				this.$emit("change", this.getData());
			},
			//打开拾取器
			openPicker(val){
				let Arr =["Y","M","T"];
				this.$refs["picker"+val].open();
				//重构年数据列表
				if(val=="Y"){
					this.pickerCreateYearList()
				}
				//关闭其他拾取器
				Arr.map((item)=>{
					if(item!=val){
						let handle = this.$refs["picker"+item];
						if(handle){
							handle.close()
						}
					}
				})
			},
			//时间拾取器打开，手动初始化滚动盒位置
			pickerTOpened(){
				this.$refs.clock.initScroll()
			},
			//拾取器翻页
			pickerTurnPage(val){
				this.pickerPage += val;
				this.pickerCreateYearList();
			},
			//拾取器生成年数据列表
			pickerCreateYearList(){
				//根据当前基准时间年生成3*5宫格，根据正负页号增减
				this.pickerListYear =[];
				if(this.baseTime){
					//前7后7填充
					for(let i=0; i<15; i++){
						this.pickerListYear.push(this.currYear+i-7+this.pickerPage*15)
					}
				}
			},
			//拾取器点击年
			pickerClickYear(val){
				let temp = new Date(this.baseTime);
				temp.setFullYear(val);
				this.baseTime = temp.getTime();
				this.pickerPage = 0;
				setTimeout(()=>{
					this.$refs["pickerY"].close();
				},300);
				this.refresh();
			},
			//拾取器点击月
			pickerClickMonth(val){
				let temp = new Date(this.baseTime);
				temp.setMonth(val-1);
				this.baseTime = temp.getTime();
				setTimeout(()=>{
					this.$refs["pickerM"].close();
				},300);
				this.refresh();
			},
			//拾取器时间变更
			pickerTimeChange(e){
				this.timeValue = e;
				if(!this.isVirtual){
					this.$emit("change", this.getData());
				}
			},
			//选中日期，检查重复
			selectItem(item){
				item["active"] = true;
				if(!this.selectList.includes(item.value)){
					this.selectList.push(item.value);
				}
			},
			//取消选中日期
			deleteItem(item){
				delete item.active;
				let idx = this.selectList.indexOf(item.value);
				if(idx != -1){
					this.selectList.splice(idx, 1)
				}
			},
			//提交事件
			submit(){
				let len = this.selectList.length,
					min = this.setting.min,
					max = this.max||0;
				if(this.isRadio&&len<1){
					this.$api.msg(this.textSetting.tipDateEmptyError, "error")
					return
				}
				if(this.isCheckbox&&(len<min||(max&&len>max))){
					let msg = max? this.textSetting.tipDateMaxError :this.textSetting.tipDateMinError;
					msg = msg.replace("${min}", min);
					msg = msg.replace("${max}", max);
					this.$api.msg(msg, "error")
					return
				}
				if(this.isRange&&len!=2){
					this.$api.msg(this.textSetting.tipDateRangeError, "error")
					return
				}
				this.$emit("submit", this.getData());
			},
			//获取结果，可外部使用
			getData(){
				let format = this.resFormat ||"timestamp";
				let res;
				switch(format){
					case "timestamp":
						if(this.isRadio){
							res = this.pickTime? this.putTime(this.selectList[0]) :this.selectList[0]
						}else{
							res = this.selectList
						}
						break; 
					case "ISO":
						if(this.isRadio){
							res = this.pickTime? this.putTime(this.selectList[0], true).toISOString() :new Date(this.selectList[0]).toISOString()
						}else{
							res = this.selectList.map((item)=>{return new Date(item).toISOString()})
						}
						break;
					case "UTC":
						if(this.isRadio){
							res = this.pickTime? this.putTime(this.selectList[0], true).toUTCString() :new Date(this.selectList[0]).toUTCString()
						}else{
							res = this.selectList.map((item)=>{return new Date(item).toUTCString()})
						}
						break;
					case "Date":
						if(this.isRadio){
							res = this.pickTime? this.putTime(this.selectList[0], true) :new Date(this.selectList[0])
						}else{
							res = this.selectList.map((item)=>{return new Date(item)})
						}
						break;
					default:
						if(this.$api.isString(format)){
							if(this.isRadio){
								res = this.pickTime? this.$api.dateFormat(this.putTime(this.selectList[0], true), {format}) :this.$api.dateFormat(this.selectList[0], {format})
							}else{
								res = this.selectList.map((item)=>{return this.$api.dateFormat(item, {format})})
							}
						}else{
							res = this.isRadio? null :[]
						}
				}
				return res
			},
			//获取日期时间合并值
			putTime(date, returnDate=false){
				let d = new Date(date);
				d.setHours(this.timeValue.hour);
				d.setMinutes(this.timeValue.minute);
				d.setSeconds(this.timeValue.second);
				if(returnDate){
					return d
				}
				return d.getTime()
			},
			//刷新日期列表
			refresh(){
				let res =[];
				let tempDate = new Date(this.baseTime), tempDate1,
					firstDate, lastDate, weekFirst, dateLast;
				tempDate.setDate(1);
				firstDate = tempDate.getTime();
				weekFirst = tempDate.getDay();
				
				tempDate1 = new Date(tempDate.getFullYear(), tempDate.getMonth()+1, 0);
				lastDate = tempDate1.getTime();
				dateLast = tempDate1.getDate();
				//补值
				for(let i=0; i<weekFirst; i++){
					let temp = new Date(firstDate + (i - weekFirst)*86400000);
					let fillItem = {
						name: temp.getDate(),
						value: temp.getTime(),
						disabled: true,
					}
					//农历
					if(this.useLunar){
						let lunarVal = lunarCalendar.solar2lunar(temp.getFullYear(), temp.getMonth()+1, temp.getDate());
						fillItem["tag"] = lunarVal.IDayCn
					}
					res.push(fillItem)
				}
				//填充当月
				for(let i=0; i<dateLast; i++){
					let value = firstDate + i*86400000;
					let fillItem = {
						name: i+1,
						value,
					}
					//判断周末
					if([0,6].includes((weekFirst +i)%7)){
						fillItem["type"] = "weekend"
					}
					//农历
					if(this.useLunar){
						let temp = new Date(value);
						let lunarVal = lunarCalendar.solar2lunar(temp.getFullYear(), temp.getMonth()+1, temp.getDate());
						fillItem["tag"] = lunarVal.IDayCn;
						//是节假日
						if(lunarVal.festival){
							fillItem["tag"] = lunarVal.festival;
							fillItem["type"] = "weekend";
						}
					}
					//判断开始结束范围
					let checkDisabled =false;
					if((this.inStart&&value<this.inStart) || (this.inEnd&&value>this.inEnd)){
						checkDisabled =true
					}
					if(this.isCheckbox){
						if( (this.max&&this.selectList.length>=this.max) &&!this.selectList.includes(value)){
							checkDisabled =true
						}
					}
					if(checkDisabled){
						fillItem["disabled"] = true
					}
					//判断选中
					if(this.isVirtual){
						for(let val of this.selectList){
							if(value<=val&&val<value+86400000){
								fillItem["subActive"] = true;
								break;
							}
						}
					}else if(this.selectList.includes(value)){
						fillItem["active"] = true
					}
					//判断今天
					if(this.today==value){
						fillItem["tag"] = this.textSetting.today;
						fillItem["tagActive"] =true;
					}
					//设置标签
					for(let j=0,len=this.inTagList.length; j<len; j++){
						let tag = this.inTagList[j];
						if(tag.value==value){
							fillItem["tag"] = tag.name;
							if(tag.event){
								fillItem["event"] = tag.event;
							}
						}
					}
					if(this.isRange){//选区
						let st=this.selectList[0], ed=this.selectList[1];
						if(st==value){
							fillItem["tag"] = this.textSetting.start;
						}else if(ed==value){
							fillItem["tag"] = this.textSetting.end;
						}
						if(this.selectList.length==2){
							if(this.selectList.includes(value)){
								fillItem["active"] = true;
								fillItem["bgActive"] = true;
							}else if(st<value && value<ed){
								fillItem["bgActive"] = true;
							}
						}
					}
					res.push(fillItem)
				}
				//补值
				let len = 42 - dateLast - weekFirst;
				for(let i=0; i<len; i++){
					let value = lastDate + i*86400000;
					let fillItem = {
						name: i+1,
						value,
						disabled: true,
					}
					//农历
					if(this.useLunar){
						let temp = new Date(value);
						let lunarVal = lunarCalendar.solar2lunar(temp.getFullYear(), temp.getMonth()+1, temp.getDate());
						fillItem["tag"] = lunarVal.IDayCn
					}
					res.push(fillItem)
				}
				//刷新圆角
				this.computeBorder(res);
				this.dateList =res;
			},
			//检查日期粘连，并设置样式
			computeBorder(list){
				let res = list? list :this.dateList,
					R = this.radius ||0;
				for(let i=0,len=res.length; i<len; i++){
					let radius = [R,R,R,R],
						bgRadius =[0,0,0,0],
						borderColor ="transparent";
					if(res[i].active||res[i].subActive){
						borderColor =[null,null,null,null];
						if(i>0 &&(res[i-1].active||res[i-1].subActive)){
							radius[0] = 0;
							radius[3] = 0;
							borderColor[3] ="transparent";
						}
						if(i<len-1 &&(res[i+1].active||res[i+1].subActive)){
							radius[1] = 0;
							radius[2] = 0;
							borderColor[1] ="transparent";
						}
					}
					//选区背景
					if(res[i].bgActive){
						if(i==0||!res[i-1].bgActive){
							bgRadius[0] =R;
							bgRadius[3] =R;
						}
						if(i==len-1||!res[i+1].bgActive){
							bgRadius[1] =R;
							bgRadius[2] =R;
						}
					}
					res[i]["radius"] = radius;
					res[i]["bgRadius"] = bgRadius;
					res[i]["borderColor"] = borderColor;
				}
				this.$forceUpdate()
			},
			//外部值变更，校验格式、
			checkNewValue(newVal){
				if(this.$api.isArray(newVal)){
					this.selectList = newVal;
					//格式标准化
					for(let i=0,len=newVal.length; i<len; i++){
						if(!this.$api.isNumber(newVal[i])){
							this.selectList[i] = new Date(newVal[i]).getTime()
						}
					}
				}else{
					let time = newVal? new Date(newVal).getTime() :(this.isRange?"":Date.now());
					this.selectList = time? [time] :[];
				}
				let today = this.clearTime(Date.now());
				this.baseTime = this.getBase(today);
				if(this.isRadio){
					if(this.selectList.length){
						this.baseTime = this.getBase(this.selectList[0])
					}else{
						this.selectList = [today];
					}
					if(this.pickTime){
						let t = new Date(this.selectList[0]);
						if(!this.useSecond){//不使用秒则置零
							t.setSeconds(0);
							this.selectList[0] = t.getTime();
						}
						this.timeValue = {
							hour: t.getHours(),
							minute: t.getMinutes(),
							second: t.getSeconds()
						};
					}
				}else{//非单选时间置0
					this.timeValue = {
						hour: 0,
						minute: 0,
						second: 0
					};
				}
				//清理时分秒毫秒
				for(let i=0,len=this.selectList.length; i<len; i++){
					this.selectList[i] = this.clearTime(this.selectList[i])
				}
				this.$emit("ready", this.getData());
				this.refresh();
			}
		},
		watch:{
			"start":{
				immediate:true,
				handler(newVal){
					this.inStart = newVal? this.$api.datePoint(newVal) :null
				}
			},
			"end":{
				immediate:true,
				handler(newVal){
					this.inEnd = newVal? this.$api.datePoint(newVal) :null
				}
			},
			"value":{
				immediate:true,
				handler(newVal){
					this.checkNewValue(newVal)
				}
			},
			"tagList":{
				handler(newVal){
					this.refresh()
				}
			},
		}
	}
</script>

<style lang="scss" scoped>
.vi_calendar{
	width: 100%;
	height: 100%;
	padding: 0.5em;
	box-sizing: border-box;
	position: relative;
	.vi_calendar_head{
		position: relative;
		border-bottom: 1px solid $vi-borColor-light;
		padding-bottom: 0.5em;
		.vi_calendar_addonL{
			position: absolute;
			left: 0.5em;
			line-height: 1;
		}
		.vi_calendar_addonR{
			position: absolute;
			right: 0.5em;
			line-height: 1;
		}
		.vi_calendar_button{
			padding: 0.25em;
		}
	}
	.vi_calendar_preMonth,
	.vi_calendar_nextMonth{
		padding: 0.25em;
	}
	.vi_calendar_currShow{
		margin: 0 0.5em;
		font-size: 105%;
		.vi_calendar_curr{
			padding: 0.25em 0;
			margin: 0 0.35em;
		}
	}
	.vi_fCenter{
		display: flex;
		justify-content: center;
		align-items: center;
	}
	.vi_calendar_body{
		padding: 0.5em 0;
		position: relative;
		overflow: hidden;
	}
	//月份背景
	.vi_calendar_bgMonth{
		color: #f8f8f8;
		position: absolute;
		z-index: -1;
		top: 0;
		right: 0;
		left: 0;
		bottom: 0;
	}
	//星期行
	.vi_calendar_rowWeek{
		width: 100%;
		display: flex;
		align-items: stretch;
		border-bottom: 1px dashed    #eee;
	}
	//日期行
	.vi_calendar_rowDate{
		width: 100%;
		display: flex;
		align-items: stretch;
	}
	.vi_calendar_item{
		width: (100/7)#{"%"};
		min-height: 2em;
		position: relative;
	}
	//选区背景
	.vi_calendar_actBg{
		position: absolute;
		z-index: 0;
		left: 0;
		top: 0;
		right: 0;
		bottom: 0;
	}
	.vi_calendar_itemBox{
		position: relative;
		z-index: 1;
	}
	.vi_calendar_itemInbox{
		text-align: center;
	}
	//拾取器
	.vi_calendar_picker{
		margin: auto;
		padding: 0 0.5em 0.5em;
		background-color: $vi-bgColor-default;
		border-radius: 0 0 0.5em 0.5em;
		&.vi_calendar_pt{
			padding-top: 0.5em;
		}
	}
	.vi_calendar_timePicker{
		padding:0.5em;
		background-color: $vi-bgColor-default;
		border-radius: 0.5em;
	}
	.vi_calendar_pickerHead{
		display: flex;
		justify-content: space-between;
		align-items: center;
		padding: 0 1em;
		border-bottom: 1px solid $vi-borColor-light;
		.iconfont{
			padding: 0.35em;
		}
	}
	.vi_calendar_pickerList{
		display: flex;
		flex-wrap: wrap;
	}
	//选择列表
	.vi_calendar_selectList{
		height: 100%;
	}
	.vi_calendar_selectItem{
		display: flex;
		align-items: center;
		justify-content: space-between;
		margin: 0 0.5em;
		padding: 0 0.5em;
		height: 3em;
		&:nth-child(even){
			background-color: #f8f8f8;
		}
	}
	//状态栏
	.vi_calendar_tips{
		line-height: 2;
		display: flex;
		align-items: center;
		.vi_calendar_text{
			margin-left: 0.5em;
			flex-shrink: 0;
		}
		.vi_calendar_scroll{
			height: 100%;
			white-space: nowrap;
		}
	}
	.vi_mr{
		margin-right: 0.5em;
	}
	.vi_mr2{
		margin-right: 1em;
	}
	.vi_mx{
		margin: 0 0.35em;
	}
	.vi_fs12{
		font-size: 120%;
	}
	//提交按钮
	.vi_calendar_submitBtn{
		margin-top: 0.5em;
	}
	.vi_calendar_tipbox{
		display: flex;
		align-items: center;
	}
	.vi_calendar_textcut{
		overflow: hidden;white-space: nowrap;text-overflow: ellipsis;
	}
	.vi_inlineBlock{
		display: inline-block;
	}
}
</style>
